package com.yihuchess.bluetoothConnect;

import android.Manifest;
import android.app.Activity;
import android.app.AlertDialog;
import android.bluetooth.BluetoothAdapter;
import android.content.ComponentName;
import android.content.Context;
import android.content.DialogInterface;
import android.content.Intent;
import android.content.ServiceConnection;
import android.content.pm.PackageManager;
import android.os.Build;
import android.os.Bundle;
import android.os.Handler;
import android.os.IBinder;
import android.os.ParcelUuid;
import android.util.Log;
import android.view.LayoutInflater;
import android.view.MotionEvent;
import android.view.View;
import android.view.View.OnClickListener;
import android.view.ViewGroup;
import android.widget.AdapterView;
import android.widget.AdapterView.OnItemClickListener;
import android.widget.Button;
import android.widget.ListView;
import android.widget.TextView;
import android.widget.Toast;

import com.nbchess.ublservice.IUBLService;
import com.nbchess.ublservice.IUBLServiceDeviceListener;
import com.nbchess.ublservice.IUBLServiceScanListener;
import com.nbchess.ublservice.UBLService;
import com.yihuchess.simplechess.R;

import java.io.Serializable;
import java.util.ArrayList;


public class BTBoardConnectActivity extends Activity {
    final static String TAG = "BTBoardConnectActivity";
    public static MyListAdapter adapter = null;
    Button scan_btn;
    static boolean mScanning = false;
    public static int mScanCnt = 0;
    public static int mScanGet = 0;
    public static int mBinded = 0;
    public static int mBtDisabled = 0;
    public static int mConnectCnt = 0;
    public static int isDefaultScan = 0;
    public static ListView listView;
    //public static View resultVIew;
    public static TextView resultVIew;
    public static ArrayList<Device> mArrayList = new ArrayList<Device>();
    public static UBLService mUBLService = null;
    public static Device mFoundDev = null;
    public static String mConnectingAddress = null;
    public static BTBoardConnectActivity instance = null;
    public static final int REQUEST_CODE = 1;
    public static final int REQ_CODE = 9;
	public final static String BtBoardName = "BtBoardName";
	public static Intent resultIntent = new Intent();
    public static Handler scanHandler = null;
    public static String recordNmae = "";

    public static final int PERMISSION_REQUEST_COARSE_LOCATION = 1;
	
	
    @Override
    protected void onCreate(Bundle savedInstanceState) {
        // TODO Auto-generated method stub
        super.onCreate(savedInstanceState);

        if (Build.VERSION.SDK_INT >= 23) {
            // Android M Permission check
            if (checkSelfPermission(Manifest.permission.ACCESS_COARSE_LOCATION) != PackageManager.PERMISSION_GRANTED) {
                if(!shouldShowRequestPermissionRationale(Manifest.permission.ACCESS_COARSE_LOCATION)) {
                    String str = getResources().getString(R.string.permission_bluetooth);
                    String msg = getResources().getString(R.string.permission_denied, str);
                    Toast.makeText(this, msg, Toast.LENGTH_SHORT).show();
                } else {
                    requestPermissions(new String[]{Manifest.permission.ACCESS_COARSE_LOCATION},
                            PERMISSION_REQUEST_COARSE_LOCATION);
                }
            }
        }

        setContentView(R.layout.layout_bt_board_connect);
        setTitle(R.string.bt_board_connect_text);

        scan_btn = (Button)findViewById(R.id.start_scan_btn); 
        scan_btn.setOnClickListener(new OnClickListener() {
            @Override
            public void onClick(View v) {
                mFoundDev = null;
                if (scanHandler != null) {
                    scanHandler.removeCallbacks(firstFindThrad); 
                    scanHandler = null;
                }
                listView.removeCallbacks(scanThread);  
                if ((mUBLService != null) && (mScanning)) {
                    mUBLService.stopScanDevice();
                }
                mScanning = false;

                if (mBtDisabled != 0) {
                    mScanCnt = 4;
                } else {
                    mScanCnt = 10;
                }
                mBtDisabled = 0;
                mScanGet = 0;
                if (mConnectCnt > 0) {
                    listView.removeCallbacks(connectThread);  
                }
                mConnectCnt = 0;
                Log.e(TAG, "press to startScanDevice");

                if ((mUBLService != null) && (mConnectingAddress != null)) {
                    mUBLService.disconnectDevice(mConnectingAddress);
                }
                //if ((mUBLService != null) && (!mScanning))
                if (mUBLService != null) { 
                    //resultVIew.setVisibility(View.GONE);
                    resultVIew.setText(R.string.label_finding_device);
                    resultVIew.setVisibility(View.VISIBLE);
                    if (mArrayList != null) {
                        mArrayList.clear();
                    }
                    if (adapter != null) {
                        adapter.clear();
                    }
                    //listView.removeAllViews();
                    adapter = new MyListAdapter(instance, mArrayList);
                    listView.setAdapter(adapter);

                    listView.postDelayed(scanThread, 1000);  
                    isDefaultScan = 0;
                    mUBLService.setDeviceListener(mIDeviceListener);
                    mUBLService.setScanListener(mIScanListener);
                    mScanning = true;
                    mUBLService.startScanDevice();
                    Log.e(TAG, "ready to startScanDevice");
                }
            }
        });

        //String osVersion = Build.VERSION.RELEASE;
        //if ((osVersion.charAt(0)) == '4' && (osVersion.charAt(1) == '.')
        //  && (osVersion.charAt(2) >= '3')) 

        if (android.os.Build.VERSION.SDK_INT >= 18) {

        } else {
            AlertDialog.Builder dialog = new AlertDialog.Builder(BTBoardConnectActivity.this);
            dialog.setTitle("Error");
            dialog.setMessage("Support Android 4.3 or above only.");
            dialog.setNegativeButton("OK",
                    new DialogInterface.OnClickListener() {

                        @Override
                        public void onClick(DialogInterface dialog, int which) {
                            System.exit(0);
                        }
                    });
            dialog.show();
            return;
        }

        instance = this;
        BluetoothAdapter ba = BluetoothAdapter.getDefaultAdapter();
        if(ba == null) {
            Log.e(TAG, "bluetooth adapter is null!");
            return;
        }
        if (!ba.isEnabled()) {
            mBtDisabled = 1;
            Intent enableBtIntent = new Intent(BluetoothAdapter.ACTION_REQUEST_ENABLE);
            startActivityForResult(enableBtIntent, REQUEST_CODE);
        } else {
            mBtDisabled = 0;
        }
        listView = (ListView) findViewById(R.id.refresh_listview);
        listView.setDivider(null);
        listView.setOnItemClickListener(mItemClickListener);
        resultVIew = (TextView) findViewById(R.id.scan_result);

        Log.e(TAG, "create bind service!!!!!!!!!!!!!!");

    }

    @Override
    protected void onResume() {
        super.onResume();
    }

    @Override
    protected void onActivityResult(int requestCode, int resultCode, Intent data) {
        // User chose not to enable Bluetooth.
        if (requestCode == REQUEST_CODE && resultCode == Activity.RESULT_CANCELED) {
            finish();
            return;
        } else if (requestCode == REQ_CODE) {
            //&& resultCode == StandardViewFragment.RST_CODE) 
            if (mFoundDev != null)
                mUBLService.disconnectDevice(mFoundDev.address);
            mUBLService = null;
            mFoundDev = null;
            mConnectingAddress = null;
            //unbindService(conn);
            //Log.e(TAG, "unbindService!!!!!!!!!!!!!!!!!");
        }

        super.onActivityResult(requestCode, resultCode, data);
    }

    private Runnable scanThread = new Runnable() {  
        public void run() {  
            if (mScanCnt > 0) {
                Log.e("scanThread", "cnt"+mScanCnt);
                mScanCnt--;
                listView.postDelayed(scanThread, 1000);  
            } else {
                Log.e("scanThread", "cnt"+mScanCnt);
                if ((mUBLService != null) && (mScanning != false)) {
                    mScanCnt = 0;
                    mUBLService.stopScanDevice();
                    Log.e(TAG, "scanThread stopScanDevice");					
                }
                mScanning = false;
            }
            addAllToList();

            if ((mScanGet == 0) && (mScanCnt <= 0)) {
                resultVIew.setText(R.string.label_no_devices);
                resultVIew.setVisibility(View.VISIBLE);
            }
        }  
    };  

    private Runnable connectThread = new Runnable() {  
        public void run() {  
            if ((mUBLService != null) && (mConnectingAddress != null)) {
                Log.e(TAG, "run connectDevice in connectThread, address:" + mConnectingAddress);
                isDefaultScan = 0;
                mUBLService.setDeviceListener(mIDeviceListener);
                mUBLService.connectDevice(mConnectingAddress, false);
            }
        }  
    };  

    public static ServiceConnection conn = new ServiceConnection() {
            @Override
        public void onServiceDisconnected(ComponentName name) {
            mUBLService = null;
            mFoundDev = null;
            mConnectingAddress = null;
        }

        @Override
        public void onServiceConnected(ComponentName name, IBinder service) {
            IUBLService binder = (IUBLService)service;
            mUBLService = binder.getService();

            if (mUBLService != null) {
                Log.e(TAG, "onServiceConnected.");

                if (mArrayList != null) {
                    mArrayList.clear();
                }
                if (adapter != null) {
                    adapter.clear();
                }
                //mUBLService.setDeviceListener(mIDeviceListener);
                //mUBLService.setScanListener(mIScanListener);
                //mUBLService.startScanDevice();
            }
        }
    };

    static IUBLServiceScanListener mIScanListener = new IUBLServiceScanListener() {
        @Override
        public void onDeviceFound(String deviceAddress, String name,
                                  int rssi, int bondState, byte[] scanRecord,
                                  ParcelUuid[] uuids) {

            if (name == null) {
                Log.e("onDeviceFound", "Device name is null");
                return;
            } else {
                Log.e("onDeviceFound", "Device name:" + name + "address : " + deviceAddress);
                if(!name.startsWith("YiHu")) {
                    return;
                }
            }

            if ((mUBLService != null) && (mScanning == false)) {
                Log.e("onDeviceFound", "stopScanDevice again.");
                mUBLService.stopScanDevice();
                mScanCnt = 0;
            }
            if(name.startsWith("YiHu")) {
                Log.e("onDeviceFound", "startsWith Yihu.");
                // hjk add SharedPreferences.
                Device mADevice = new Device();
                mADevice.address = deviceAddress;
                mADevice.name = name;
                mADevice.rssi = rssi;
                mADevice.bondState = bondState;
                mADevice.scanReadData = scanRecord;
                mADevice.uuids = uuids;

                if (isDefaultScan == 0) {
                    Log.e("onDeviceFound", ": isDefaultScan 0.");
                    if (instance != null) {
                        instance.addDevice(mADevice);
                    }
                    return;
                } 
                for (Device mTemp : mArrayList) {
                    if (mTemp.address.equals(mADevice.address)) {
                        return;
                    }
                }
                mArrayList.add(mADevice);
            }
        }
    };

    final static IUBLServiceDeviceListener mIDeviceListener = new IUBLServiceDeviceListener() {
        @Override
        public void onDeviceMessageSend(int type, String deviceAddress, int param1, int param2, int[] value) {
            //Log.e(TAG, "type:" + type + "address: " + deviceAddress + "param1: " + param1);
        }

        @Override
        public void onDeviceCharacteristicFound(boolean found) {
            Device mFirstOne = null;

            if(found) {
                Log.e(TAG, "onDeviceCharacteristicFound.");
                //intent.putExtra("Device", mFoundDev);
                
                for (Device mTemp : mArrayList) {
                    if (mFirstOne == null) {
                        mFirstOne = mTemp;
                    }
                    if (mTemp.address.equals(mConnectingAddress)) {
                        mFoundDev = mTemp;
                    }
                }
                if (mFoundDev == null) {
                    mFoundDev = mFirstOne;
                    if (mFoundDev == null) {
                        Log.e(TAG, "mFoundDev is null. and device list is null!");
                    } else {
                        Log.e(TAG, "mFoundDev is null. get the 1st:" + mFoundDev.name);
                    }
                }
            } else {
                Log.e(TAG, "not found, disconnectDevice.");
                if (mConnectingAddress != null)
                    mUBLService.disconnectDevice(mConnectingAddress);
                mFoundDev = null;
                mConnectingAddress = null;
            }

            if (mScanning) {
                Log.e(TAG, "after found stopScanDevice");
                mUBLService.stopScanDevice();
            }
            mScanning = false;
            mScanCnt = 0;
            mScanGet = 0;

            if (isDefaultScan != 0) {
                Log.e(TAG, "isDefaultScan");
                return;
            }
            if (mFoundDev != null) {
                if (mFoundDev.name != null) {
			        resultIntent.putExtra(BtBoardName, mFoundDev.name);
			        Log.e(TAG, "send name:" + mFoundDev.name);
                }
            }
            if (instance != null) {
                Log.e(TAG, "isDefaultScan 0");
			    instance.setResult(RESULT_OK, resultIntent);
			    instance.finish();
            }
        }
    };

    OnItemClickListener mItemClickListener = new OnItemClickListener() {
        @Override
        public void onItemClick(AdapterView<?> parent, View view,
                int position, long id) {

            listView.removeCallbacks(scanThread);  
            if (mScanning) {
                mScanning = false;
                mScanCnt = 0;
                mScanGet = 0;
                mUBLService.stopScanDevice();
                Log.e(TAG, "item stopScanDevice");
            }
            if (mArrayList != null && !mArrayList.isEmpty() && position >= 0) {
                Device mDev = mArrayList.get(position);
                mConnectingAddress = mDev.address;
                Log.e(TAG, "call connectDevice, address:" + mConnectingAddress);
                
                /* avoid reconnect too quickly, cause some unkown connection bug. */
                listView.removeCallbacks(connectThread);  
                if (mConnectCnt == 0) {
                    listView.postDelayed(connectThread, 200);  
                } else {
                    listView.postDelayed(connectThread, 2000);  
                }
                mConnectCnt++;
            }
        }
    };

    @Override
    public void onDestroy() {
        try {
            //unbindService(conn);
            Log.e(TAG, "onDestroy !!");
            // todo
        if ((mUBLService != null) && (mScanning != false)) {
            mScanCnt = 0;
            mScanning = false;
            mUBLService.stopScanDevice();
            Log.e(TAG, "onDestroy stopScanDevice");					
        }
        listView.removeCallbacks(scanThread);  
        listView.removeCallbacks(connectThread);  
        } catch (Exception e) {
            // todo
            Log.e(TAG, e.getMessage());
        }

        super.onDestroy();
    }

    
    @Override
    public boolean onTouchEvent(MotionEvent event) {
        // TODO Auto-generated method stub
        return true;
    }

    public static UBLService getUBLService() {
        return mUBLService;
    }

    public static void setBtDevice(Device newDevice) {
        mFoundDev = newDevice;
    }

    public static Device getBtDevice() {
        return mFoundDev;
    }

    public static boolean isScanning() {
        if (mScanning || (mScanCnt > 0))
            return true;
        return false;
    }

    //final static IUBLServiceDeviceListener mFirstDeviceListener = new IUBLServiceDeviceListener()
    //static IUBLServiceScanListener mFirstScanListener = new IUBLServiceScanListener() {

    public static Runnable firstFindThrad = new Runnable() {  
        public void run() {  
            if (mScanCnt > 0) {
                Log.e(TAG, "firstFindThrad" + "cnt"+mScanCnt);

                if ((mUBLService != null) && (!mScanning)) {
                    isDefaultScan = 1;
                    mUBLService.setDeviceListener(mIDeviceListener);
                    mUBLService.setScanListener(mIScanListener);
                    mScanning = true;
                    mUBLService.startScanDevice();
                    Log.e(TAG, "startScanDevice in start" + mScanCnt);
                }
                if ((mUBLService != null) && (mArrayList != null)) {
                    for (Device mTemp : mArrayList) {
                        if ((mTemp == null) || (recordNmae == null)) {
                            continue;
                        }
                        if ((mTemp.name != null) && (mTemp.name.equals(recordNmae))) {
                            Log.e(TAG, "in start find: " + recordNmae);
                            mConnectingAddress = mTemp.address;
                            Log.e(TAG, "firstFindThrad stopScanDevice");
                            mUBLService.stopScanDevice();
                            mScanning = false;
                            mScanCnt = 0;
                            scanHandler.postDelayed(this, 200);  
                            return;
                        }
                    }
                }
                mScanCnt--;
                scanHandler.postDelayed(this, 360);  
            } else {
                Log.e(TAG, "firstFindThrad" + "cnt"+mScanCnt);
                if ((mScanCnt == 0) && (mUBLService != null)) {
                    Log.e(TAG, "firstFindThrad 2 stopScanDevice");
                    mUBLService.stopScanDevice();
                }
                mScanning = false;

                if ((mConnectingAddress != null) && (mUBLService != null)) {
                    if ((mFoundDev == null) && (mScanCnt > -2)) {
                        isDefaultScan = 1;
                        mUBLService.setDeviceListener(mIDeviceListener);
                        Log.e(TAG, "first call connectDevice");
                        mUBLService.connectDevice(mConnectingAddress, false);
                        scanHandler.postDelayed(this, 3600);  
                        mScanCnt--;
                    } else {
                        mScanCnt = 0;
                    }
                } 
            }
        } 
    };  

    public static int bindAndConnectDevice(Activity caller, String deviceName) {
        BluetoothAdapter ba = BluetoothAdapter.getDefaultAdapter();
        if (!ba.isEnabled()) {
            mUBLService = null;
            mFoundDev = null;
            mConnectingAddress = null;
            return -1;
        }
        if (mUBLService == null) {
            bindUBLService(caller);
            isDefaultScan = 1;
        }
        scanHandler = new Handler();
        mScanCnt = 20;
        mScanGet = 0;
        if ((mUBLService != null) && (mScanning != false)) {
            Log.e(TAG, "in start mScanning isn't false!");
            mUBLService.stopScanDevice();
        }
        mScanning = false;
        recordNmae = deviceName;
        Log.e(TAG, "in start to startScanDevice");

        if (mArrayList != null) {
            mArrayList.clear();
        }
        mFoundDev = null;
        mConnectingAddress = null;
        scanHandler.postDelayed(firstFindThrad, 200);  
        return 0;
    }

    public static int bindUBLService(Activity caller) {
        Intent service = new Intent("com.nbchess.ublservice.UBLService");
        service.setPackage(caller.getPackageName());
        //service.setPackage("com.chunquedong.chungo");

        if (mUBLService == null) {
            caller.bindService(service, conn, Context.BIND_AUTO_CREATE);
            mBinded = 1;
        }
        if (mUBLService != null) {
            isDefaultScan = 0;
            mUBLService.setDeviceListener(mIDeviceListener);
        }
        Log.e(TAG, UBLService.class.getName());
        return 0;
    }

    public static int unbindUBLService(Activity caller) {
        if (scanHandler != null) {
            scanHandler.removeCallbacks(firstFindThrad); 
            scanHandler = null;
        }
        if ((mUBLService != null) && (mBinded != 0)) {
            if (mConnectingAddress != null) {
                Log.e(TAG, "unbindUBLService stopScanDevice");
                mUBLService.stopScanDevice();
                mUBLService.disconnectDevice(mConnectingAddress);
                isDefaultScan = 0;
                mUBLService.setDeviceListener(null);
                mUBLService.setScanListener(null);
            }
            caller.unbindService(conn);
        }

        mScanning = false;
        mScanCnt = 0;
        mScanGet = 0;
        mBinded = 0;
        mUBLService = null;
        mFoundDev = null;
        mConnectingAddress = null;
        return 0;
    }

    public static class Device implements Serializable {
        private static final long serialVersionUID = -5961124837206924220L;
        public String address;
        public String name;
        public int bondState;
        public int rssi;
        public byte[] scanReadData;
        public ParcelUuid[] uuids;
    }

    void addDevice(final Device mDevice) {

        for (Device mTemp : mArrayList) {
            if (mTemp.address.equals(mDevice.address)) {
                mTemp.rssi = mDevice.rssi;

                runOnUiThread(new Runnable() {
                    @Override
                    public void run() {
                        if (adapter != null) {
                            adapter.notifyDataSetChanged();
                        }
                    }
                });
                return;
            }
        }

        mArrayList.add(mDevice);
    }

    void addAllToList() {
        if ((mArrayList.size() == 0) || (mScanGet == mArrayList.size())) {
            return;
        }
        mScanGet = mArrayList.size();
        Log.e(TAG, "size:" + mScanGet);

        adapter = new MyListAdapter(this, mArrayList);
        listView.setAdapter(adapter);

        resultVIew.setVisibility(View.GONE);
    }

    private class MyListAdapter extends ArrayAdapter<Device> {

        private Context mContext;

        private LayoutInflater mInflater;

        ArrayList<Device> items;

        public MyListAdapter(Context context, ArrayList<Device> items) {
            super(items);
            Log.e(TAG, "MyListAdapter");
            mContext = context;
            mInflater = LayoutInflater.from(mContext);
            this.items = items;
        }

        public View getView(int position, View convertView, ViewGroup parent) {
            Device sDevice = items.get(position);
            View v = mInflater.inflate(R.layout.main_page_listview_item,
                    null);

            TextView mName = (TextView) v.findViewById(R.id.big_name);
            mName.setText(sDevice.name);

            TextView mRssi = (TextView) v.findViewById(R.id.service);
            mRssi.setText("Rssi: " + sDevice.rssi);

            TextView mAddress = (TextView) v.findViewById(R.id.name);
            mAddress.setText("Address: " + sDevice.address);
            //setAddress(position, sDevice.address);
            return v;
        }
    }

    @Override
    public void onRequestPermissionsResult(int requestCode, String permissions[], int[] grantResults) {
        switch (requestCode) {
            case PERMISSION_REQUEST_COARSE_LOCATION:
                if (grantResults != null && grantResults.length > 0 && grantResults[0] == PackageManager.PERMISSION_GRANTED) {
                    Log.d(TAG, "request coarse location permission ok");
                } else {
                    Log.e(TAG, "request coarse location permission fail");
                    String str = getResources().getString(R.string.permission_bluetooth);
                    String msg = getResources().getString(R.string.permission_denied, str);
                    Toast.makeText(this, msg, Toast.LENGTH_SHORT).show();
                }
                break;
            default:
                break;
        }
    }

}


